#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>
#include "Cond.hpp"
#include "Mutex.hpp"


namespace BlockQueueModule
{
    using namespace LockModule;
    using namespace CondModule;
    
    static const int gcap = 10;

    template<typename T>
    class BlockQueue
    {
        bool IsFull() { return _q.size() == _cap; }
        bool IsEmpty() { return _q.empty(); }
    public:
        BlockQueue(int cap = gcap)
        :_cap(cap)
        ,_pwait_num(0)
        ,_cwait_num(0)
        { }

        void Equeue(const T& in)
        {
            LockGuard lockguard(_mutex);
            while (IsFull())
            {
                _pwait_num++;
                _productor_cond.Wait(_mutex);
                _pwait_num--;
            }
            _q.push(in);
            if (_cwait_num)
            {
                _consumer_cond.Notify();
            }
        }

        void Pop(T* out)
        {
            LockGuard lockguard(_mutex);
            while (IsEmpty())
            {
                _cwait_num++;
                _consumer_cond.Wait(_mutex);
                _cwait_num--;
            }
            *out = _q.front();
            _q.pop();
            if (_pwait_num)
            {
                _productor_cond.Notify();
            }
        }


        ~BlockQueue()
        {}
    private:
        std::queue<T> _q;               // 保存数据的容器,临界资源
        int _cap;                       // bq最大容量
        Mutex _mutex;                   // 互斥量
        Cond _productor_cond;           // 生产者条件变量
        Cond _consumer_cond;            // 消费者条件变量
        int _pwait_num;
        int _cwait_num;
    };


    // static const int gcap = 10;

    // template<typename T>
    // class BlockQueue
    // {
    //     bool IsFull() { return _q.size() == _cap; }
    //     bool IsEmpty() { return _q.empty(); }
    // public:
    //     BlockQueue(int cap = gcap)
    //     :_cap(cap)
    //     ,_pwait_num(0)
    //     ,_cwait_num(0)
    //     {
    //         pthread_mutex_init(&_mutex, nullptr);
    //         pthread_cond_init(&_productor_cond, nullptr);
    //         pthread_cond_init(&_consumer_cond, nullptr);
    //     }

    //     void Equeue(const T& in)
    //     {
    //         pthread_mutex_lock(&_mutex);
    //         while (IsFull())
    //         {
    //             _pwait_num++;
    //             pthread_cond_wait(&_productor_cond, &_mutex);
    //             _pwait_num--;
    //         }
    //         _q.push(in);
    //         if (_cwait_num)
    //         {
    //             pthread_cond_signal(&_consumer_cond);
    //         }
    //         pthread_mutex_unlock(&_mutex);
    //     }

    //     void Pop(T* out)
    //     {
    //         pthread_mutex_lock(&_mutex);
    //         while (IsEmpty())
    //         {
    //             _cwait_num++;
    //             pthread_cond_wait(&_consumer_cond, &_mutex);
    //             _cwait_num--;
    //         }
    //         *out = _q.front();
    //         _q.pop();
    //         if (_pwait_num)
    //         {
    //             pthread_cond_signal(&_productor_cond);
    //         }
    //         pthread_mutex_unlock(&_mutex);
    //     }


    //     ~BlockQueue()
    //     {
    //         pthread_mutex_destroy(&_mutex);
    //         pthread_cond_destroy(&_productor_cond);
    //         pthread_cond_destroy(&_consumer_cond);
    //     }
    // private:
    //     std::queue<T> _q;               // 保存数据的容器,临界资源
    //     int _cap;                       // bq最大容量
    //     pthread_mutex_t _mutex;         // 互斥量
    //     pthread_cond_t _productor_cond; // 生产者条件变量
    //     pthread_cond_t _consumer_cond;  // 消费者条件变量
    //     int _pwait_num;
    //     int _cwait_num;
    // };
}